package com.hakedbyme.cokey.helper;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.ByteBuffer;
import java.util.Arrays;



@Component
public class DnsHelper {


//    @Autowired
////    private DatabaseHelper databaseHelper = new DatabaseHelper();
////
////    private CommonHelper commonHelper = new CommonHelper();

    private static DatagramSocket udpSocket;

    private int port = 53;

    @Value("${domain}")
    private String host = "cokey.xyz";
    private byte[] defaultIp = ByteBuffer.allocate(4).putInt(ipToInt("220.181.112.244")).array();

    private static Thread daemonThread;
    private static Boolean daemoned = false;

    private Logger logger = LoggerFactory.getLogger(getClass());


    @Async
    public void daemon(String action) {
        if (action.equals("stop")) {
            try {
                if (daemoned.equals(true)) {
                    daemonThread.stop();
                    udpSocket.close();
                }
                daemoned = false;
                Thread.currentThread().stop();

            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }

        logger.info("Dns deamon started, test case: `ping -c 4 test." + host + "`");
        try {
            daemoned = true;
            daemonThread = Thread.currentThread();
            udpSocket = new DatagramSocket(port);
            byte[] udpData = new byte[512];

            while (true && daemoned) {
                try {

                    DatagramPacket udpPacket = new DatagramPacket(udpData, udpData.length);
                    udpSocket.receive(udpPacket);
                    StringBuilder queryName = new StringBuilder();
                    int idx = 12;// skip header
                    int len = udpData[idx];
                    while (len > 0) {
                        queryName.append(".").append(new String(udpData, idx + 1, len));
                        idx += len + 1;
                        len = udpData[idx];
                    }
                    logger.info("DNS Query Received !");
                    logger.info("QueryName: " + queryName.toString());
                    logger.info("Address: " + udpPacket.getAddress());
                    logger.info("Socket Address: " + udpPacket.getSocketAddress());

//                    try {
//                        databaseHelper.insert("dns", commonHelper.udpJson(udpSocket, queryName));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//
//                    }

                    if (queryName.length() > 0) {
                        String name = queryName.substring(1).toLowerCase();

                        int type = udpData[idx + 1] * 256 + udpData[idx + 2];


                        if ((!name.equals(host)) && type != 1 && (!name.endsWith("." + host))) {
                            // type = 1 A记录,其他的忽略
                            continue;
                        }


                        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                        byteArrayOutputStream.write(new byte[]{udpData[0], udpData[1], (byte) 0x81, (byte) 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00});


                        byte[] requestQuery = Arrays.copyOfRange(udpData, 12, idx + 5);
                        byteArrayOutputStream.write(requestQuery);
                        byteArrayOutputStream.write(requestQuery);
                        byteArrayOutputStream.write(ByteBuffer.allocate(4).putInt(name.equals(host) ? 3600 : 10).array());// ttl


                        byteArrayOutputStream.write(new byte[]{0x00, 0x04});
                        byteArrayOutputStream.write(defaultIp);


                        byte[] sendData = byteArrayOutputStream.toByteArray();
                        DatagramPacket sendPacket = new DatagramPacket(
                                sendData, sendData.length,
                                udpPacket.getAddress(),
                                udpPacket.getPort());
                        udpSocket.send(sendPacket);

                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            daemoned = false;

        }


    }

    private int ipToInt(String ipAddress) {
        long result = 0;
        String[] ipAddressInArray = ipAddress.split("\\.");
        for (int i = 3; i >= 0; i--) {
            long ip = Long.parseLong(ipAddressInArray[3 - i]);
            result |= ip << (i * 8);
        }
        return (int) result;
    }


}


